package top.hudk.rpc.rpc1;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 作用：RPC测试服务端Service
 *
 * @author hudk
 * @date 2020/12/9 23:24
 */
public class Service {

    /**
     * 端口
     */
    private static int port = 10086;

    /**
     * 模拟接口与实现类的映射关系
     * 实际开发中，可以使用配置文件来绑定接口与实现类的关系
     */
    private static Map<String, String> propertis = new HashMap<>();

    static {
        propertis.put("top.hudk.rpc.rpc1.IUserService", "top.hudk.rpc.rpc1.UserService");
    }

    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        ObjectInputStream objectInputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            serverSocket = new ServerSocket(port);
            while (true) {
                System.out.println("等待客户端连接...");
                //阻塞等待新的连接进来
                socket = serverSocket.accept();
                System.out.println("客户端连接成功");
                //对象输入流
                objectInputStream = new ObjectInputStream(socket.getInputStream());
                //从网络获取信息：方法的调用信息类
                RpcMsg msg = (RpcMsg) objectInputStream.readObject();
                System.out.println("接收到的消息为:========" + msg);
                socket.shutdownInput();
                //从接口和实现类映射表中，查找出接口类型对应绑定的实现类全类名
                String implClassName = propertis.get(msg.getClassName());
                System.out.println("实际执行的实现类名称为:========" + implClassName);
                //根据方法的信息，利用反射实例化并执行对应方法
                Class clazz = Class.forName(implClassName);
                Method method = clazz.getMethod(msg.getMethodName(), msg.getMethodParamType());
                //执行实际的实现类实例的方法
                Object obj = method.invoke(clazz.newInstance(), msg.getArgs());
                System.out.println("执行成功，返回内容:========" + obj);
                //如果方法不是void，则将结果回写客户端
                if (!Objects.equals(Void.class, method.getReturnType())) {
                    objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                    objectOutputStream.writeObject(obj);
                    socket.shutdownOutput();
                    objectOutputStream.close();
                }
                objectInputStream.close();
                socket.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //逐一释放资源
            if (objectOutputStream != null) {
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (objectInputStream != null) {
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
